1 : <?php
2 : /**
3 : * Container implementation.
4 : *
5 : * PHP Version 5
6 : *
7 : * @category Ding
8 : * @package Container
9 : * @subpackage Impl
10 : * @author Marcelo Gornstein <marcelog@gmail.com>
11 : * @license http://marcelog.github.com/ Apache License 2.0
12 : * @link http://marcelog.github.com/
13 : *
14 : * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
15 : *
16 : * Licensed under the Apache License, Version 2.0 (the "License");
17 : * you may not use this file except in compliance with the License.
18 : * You may obtain a copy of the License at
19 : *
20 : * http://www.apache.org/licenses/LICENSE-2.0
21 : *
22 : * Unless required by applicable law or agreed to in writing, software
23 : * distributed under the License is distributed on an "AS IS" BASIS,
24 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 : * See the License for the specific language governing permissions and
26 : * limitations under the License.
27 : *
28 : */
29 : namespace Ding\Container\Impl;
30 :
31 : use Ding\Helpers\ErrorHandler\ErrorInfo;
32 :
33 : use Ding\Bean\IBeanDefinitionProvider;
34 : use Ding\Cache\Impl\DummyCacheImpl;
35 : use Ding\Bean\Provider\Core;
36 : use Ding\Resource\Impl\IncludePathResource;
37 : use Ding\Resource\Impl\FilesystemResource;
38 : use Ding\Resource\Impl\URLResource;
39 : use Ding\Cache\Locator\CacheLocator;
40 : use Ding\Container\IContainer;
41 : use Ding\Aspect\AspectManager;
42 : use Ding\Aspect\InterceptorDefinition;
43 : use Ding\Aspect\AspectDefinition;
44 : use Ding\Aspect\Interceptor\IDispatcher;
45 : use Ding\Aspect\Interceptor\DispatcherImpl;
46 : use Ding\Reflection\ReflectionFactory;
47 : use Ding\Bean\Lifecycle\BeanLifecycle;
48 : use Ding\Bean\Lifecycle\BeanLifecycleManager;
49 : use Ding\Bean\Factory\Exception\BeanFactoryException;
50 : use Ding\Bean\BeanConstructorArgumentDefinition;
51 : use Ding\Bean\BeanDefinition;
52 : use Ding\Bean\BeanPropertyDefinition;
53 : use Ding\MessageSource\IMessageSource;
54 :
55 : /**
56 : * Container implementation.
57 : *
58 : * PHP Version 5
59 : *
60 : * @category Ding
61 : * @package Container
62 : * @subpackage Impl
63 : * @author Marcelo Gornstein <marcelog@gmail.com>
64 : * @license http://marcelog.github.com/ Apache License 2.0
65 : * @link http://marcelog.github.com/
66 : */
67 : class ContainerImpl implements IContainer
68 : {
69 : /**
70 : * Signals to handle.
71 : * @var array
72 : */
73 : private $_signals = array(
74 : SIGQUIT, SIGHUP, SIGINT, SIGCHLD, SIGTERM, SIGUSR1, SIGUSR2
75 : );
76 : /**
77 : * Logger.
78 : * @var Logger
79 : */
80 : private $_logger;
81 :
82 : /**
83 : * Cache for isDebugEnabled()
84 : * @var boolean
85 : */
86 : private $_logDebugEnabled;
87 :
88 : /**
89 : * Dispatcher to be cloned for proxy.
90 : * @var DispatcherImpl
91 : */
92 : private $_dispatcherTemplate = null;
93 :
94 : /**
95 : * MessageSource implementation.
96 : * @var IMessageSource
97 : */
98 : private $_messageSource = false;
99 : /**
100 : * Default options.
101 : * @var array
102 : */
103 : private static $_options = array(
104 : 'bdef' => array(),
105 : 'properties' => array(),
106 : 'drivers' => array()
107 : );
108 :
109 : /**
110 : * Registered shutdown methods for beans (destroy-methods).
111 : * @var array
112 : */
113 : private $_shutdowners = array();
114 :
115 : /**
116 : * Beans already instantiated.
117 : * @var object[]
118 : */
119 : private $_beans;
120 :
121 : /**
122 : * Holds our beans cache.
123 : * @var ICache
124 : */
125 : private $_beanCache;
126 :
127 : /**
128 : * Beans already instantiated.
129 : * @var BeanDefinition[]
130 : */
131 : private $_beanDefs;
132 :
133 : /**
134 : * Beans aliases.
135 : * @var string[]
136 : */
137 : private $_beanAliases;
138 :
139 : /**
140 : * Holds our bean definitions cache.
141 : * @var ICache
142 : */
143 : private $_beanDefCache;
144 :
145 : /**
146 : * Container instance.
147 : * @var ContainerImpl
148 : */
149 : private static $_containerInstance = false;
150 :
151 : /**
152 : * The aspect manager.
153 : * @var AspectManager
154 : */
155 : private $_aspectManager = null;
156 :
157 : /**
158 : * The lifecycle manager.
159 : * @var BeanLifecycleManager
160 : */
161 : private $_lifecycleManager = null;
162 :
163 : /**
164 : * Resources multiton.
165 : * @var IResource[]
166 : */
167 : private $_resources = false;
168 :
169 : /**
170 : * The event listeners
171 : * @var string[]
172 : */
173 : private $_eventListeners = false;
174 :
175 : /**
176 : * Bean Definition providers.
177 : * @var IBeanDefinitionProvider[]
178 : */
179 : private $_beanDefinitionProviders = array();
180 :
181 : /**
182 : * The last error message is saved, just to avoid logging repeated messages.
183 : * @var string
184 : */
185 : private $_lastErrorMessage;
186 :
187 : /**
188 : * A ReflectionFactory implementation
189 : * @var IReflectionFactory
190 : */
191 : private $_reflectionFactory;
192 :
193 : /**
194 : * A Proxy factory implementation.
195 : * @var Proxy
196 : */
197 : private $_proxyFactory;
198 :
199 : /**
200 : * Properties configured when instantiating the container and by others,
201 : * like when using a PropertiesHolder.
202 : *
203 : * @var string[]
204 : */
205 : private $_properties;
206 :
207 : /**
208 : * Prevent serialization.
209 : *
210 : * @return array
211 : */
212 : public function __sleep()
213 : {
214 1 : return array('_aspectManager', '_lifecycleManager');
215 : }
216 :
217 : /**
218 : * (non-PHPdoc)
219 : * @see Ding\Bean.IBeanDefinitionProvider::getBeanDefinitionByClass()
220 : */
221 : public function getBeanDefinitionByClass($class)
222 : {
223 3 : foreach ($this->_beanDefinitionProviders as $provider) {
224 3 : $beanDefinition = $provider->getBeanDefinitionByClass($class);
225 3 : }
226 3 : }
227 : /**
228 : * Returns a bean definition.
229 : *
230 : * @param string $name Bean name.
231 : *
232 : * @return BeanDefinition
233 : * @throws BeanFactoryException
234 : */
235 : public function getBeanDefinition($name)
236 : {
237 277 : $beanName = $name . '.beandef';
238 277 : if (isset($this->_beanAliases[$name])) {
239 2 : $name = $this->_beanAliases[$name];
240 2 : }
241 277 : if (isset($this->_beanDefs[$name])) {
242 20 : return $this->_beanDefs[$name];
243 : }
244 :
245 277 : $beanDefinition = null;
246 277 : if ($this->_beanDefCache !== null) {
247 277 : $beanDefinition = $this->_beanDefCache->fetch($beanName, $result);
248 277 : }
249 277 : if ($beanDefinition) {
250 69 : $this->_beanDefs[$name] = $beanDefinition;
251 69 : return $beanDefinition;
252 : }
253 277 : foreach ($this->_beanDefinitionProviders as $provider) {
254 277 : $beanDefinition = $provider->getBeanDefinition($name);
255 277 : if ($beanDefinition) {
256 277 : $beanDefinition->setClass($this->_searchAndReplaceProperties(
257 277 : $beanDefinition->getClass()
258 277 : ));
259 277 : break;
260 : }
261 277 : }
262 277 : if (!$beanDefinition) {
263 259 : throw new BeanFactoryException('Unknown bean: ' . $name);
264 : }
265 277 : $beanDefinition = $this->_lifecycleManager->afterDefinition($beanDefinition);
266 277 : $this->_beanDefs[$beanName] = $beanDefinition;
267 277 : $this->_beanDefCache->store($beanName, $beanDefinition);
268 277 : foreach ($beanDefinition->getAliases() as $alias) {
269 19 : $this->_beanAliases[$alias] = $name;
270 277 : }
271 277 : return $beanDefinition;
272 : }
273 :
274 : /**
275 : * Will try to search and replace the properties found in the given
276 : * value.
277 : *
278 : * @param string $value
279 : *
280 : * @return string
281 : */
282 : private function _searchAndReplaceProperties($value)
283 : {
284 277 : if (is_string($value)) {
285 277 : foreach ($this->_properties as $k => $v) {
286 49 : if (strpos($value, $k) !== false) {
287 19 : if (is_string($v)) {
288 19 : $value = str_replace($k, $v, $value);
289 19 : } else {
290 12 : $value = $v;
291 : // Assigned value is not a string, so we cant use
292 : // strpos anymore on it (i.e: cant continue replacing)
293 12 : break;
294 : }
295 19 : }
296 277 : }
297 277 : }
298 277 : return $value;
299 : }
300 :
301 : /**
302 : * Takes care of transforming a scalar value for a property or constructor
303 : * argument, into a an actual value (i.e: if its a resource://, loading it
304 : * first).
305 : *
306 : * @param mixed $value The value
307 : *
308 : * @return mixed
309 : */
310 : private function _loadValue($value)
311 : {
312 277 : $value = $this->_searchAndReplaceProperties($value);
313 277 : if (is_string($value) && strpos($value, 'resource://') === 0) {
314 2 : $value = substr($value, 11);
315 2 : return $this->getResource($value);
316 : }
317 277 : return $value;
318 : }
319 :
320 : /**
321 : * This will resolve a property (or constructor arg) definition to a final
322 : * value, being a bean reference, array of other properties (or
323 : * constructor args), etc.
324 : *
325 : * @param BeanPropertyDefinition|BeanConstructorArgumentDefinition $what
326 : *
327 : * @return void
328 : */
329 : private function _getValueFromDefinition($what)
330 : {
331 277 : $value = null;
332 277 : if ($what->isBean()) {
333 277 : $value = $this->getBean($what->getValue());
334 277 : } else if ($what->isArray()) {
335 53 : $value = array();
336 53 : foreach ($what->getValue() as $k => $v) {
337 53 : $value[$k] = $this->_getValueFromDefinition($v);
338 53 : }
339 277 : } else if ($what->isCode()) {
340 24 : $value = eval($what->getValue());
341 24 : } else {
342 277 : $value = $this->_loadValue($what->getValue());
343 : }
344 277 : return $value;
345 : }
346 :
347 : /**
348 : * Resolves all values for constructor arguments definitions in a
349 : * bean definition.
350 : *
351 : * @param BeanDefinition $definition
352 : *
353 : * @return object
354 : */
355 : private function _getConstructorValuesForDefinition($definition)
356 : {
357 277 : $args = array();
358 277 : foreach ($definition->getArguments() as $argument) {
359 277 : $value = $this->_getValueFromDefinition($argument);
360 277 : if ($argument->hasName()) {
361 4 : $name = $argument->getName();
362 4 : $args[$name] = $value;
363 4 : } else {
364 277 : $args[] = $value;
365 : }
366 277 : }
367 277 : return $args;
368 : }
369 :
370 : /**
371 : * Instantiates a bean using the constructor.
372 : *
373 : * @param BeanDefinition $definition
374 : *
375 : * @return object
376 : */
377 : private function _instantiateByConstructor(BeanDefinition $definition)
378 : {
379 277 : $class = $definition->getClass();
380 277 : if ($definition->hasProxyClass()) {
381 24 : $class = $definition->getProxyClassName();
382 24 : }
383 277 : $rClass = $this->_reflectionFactory->getClass($class);
384 277 : $factoryMethod = $rClass->getConstructor();
385 277 : if ($factoryMethod !== null) {
386 277 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
387 277 : if (empty($args)) {
388 277 : return $rClass->newInstanceArgs();
389 : } else {
390 277 : return $rClass->newInstanceArgs($args);
391 : }
392 : } else {
393 277 : return $rClass->newInstanceArgs();
394 : }
395 : }
396 :
397 : /**
398 : * Instantiates a bean using a factory class.
399 : *
400 : * @param BeanDefinition $definition
401 : *
402 : * @return object
403 : */
404 : private function _instantiateByFactoryClass(BeanDefinition $definition)
405 : {
406 277 : $class = $definition->getClass();
407 277 : $rClass = $this->_reflectionFactory->getClass($class);
408 277 : $factoryMethodName = $definition->getFactoryMethod();
409 277 : $factoryMethod = $rClass->getMethod($factoryMethodName);
410 277 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
411 277 : return forward_static_call_array(array($class, $factoryMethodName), $args);
412 : }
413 :
414 : /**
415 : * Instantiates a bean using a factory bean.
416 : *
417 : * @param BeanDefinition $definition
418 : *
419 : * @return object
420 : */
421 : private function _instantiateByFactoryBean(BeanDefinition $definition)
422 : {
423 70 : $factoryBean = $this->getBean($definition->getFactoryBean());
424 70 : $refObject = new \ReflectionObject($factoryBean);
425 70 : $factoryMethod = $refObject->getMethod($definition->getFactoryMethod());
426 70 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
427 70 : return $factoryMethod->invokeArgs($factoryBean, $args);
428 : }
429 :
430 : private function _sortArgsWithNames(BeanDefinition $definition, \ReflectionMethod $rMethod)
431 : {
432 277 : $args = $this->_getConstructorValuesForDefinition($definition);
433 277 : $callArgs = array();
434 277 : foreach ($rMethod->getParameters() as $parameter) {
435 277 : $parameterName = $parameter->getName();
436 277 : if (isset($args[$parameterName])) {
437 4 : $callArgs[] = $args[$parameterName];
438 4 : unset($args[$parameterName]);
439 4 : }
440 277 : }
441 277 : foreach ($args as $value) {
442 277 : $callArgs[] = $value;
443 277 : }
444 277 : return $callArgs;
445 : }
446 :
447 : /**
448 : * Instantiates a bean.
449 : *
450 : * @param BeanDefinition $definition
451 : *
452 : * @return object
453 : */
454 : private function _instantiate(BeanDefinition $definition)
455 : {
456 277 : if ($definition->isCreatedByConstructor()) {
457 277 : return $this->_instantiateByConstructor($definition);
458 277 : } else if ($definition->isCreatedWithFactoryBean()) {
459 70 : return $this->_instantiateByFactoryBean($definition);
460 : } else {
461 277 : return $this->_instantiateByFactoryClass($definition);
462 : }
463 : }
464 :
465 : /**
466 : * Creates whatever beans this definition depends on.
467 : *
468 : * @return void
469 : */
470 : private function _createBeanDependencies(BeanDefinition $definition)
471 : {
472 277 : foreach ($definition->getDependsOn() as $depBean) {
473 6 : $this->getBean(trim($depBean));
474 277 : }
475 277 : }
476 :
477 : /**
478 : * Will inject into the given dispatcher the necessary information to
479 : * aspects will be run correctly.
480 : *
481 : * @throws BeanFactoryException
482 : * @return void
483 : */
484 : private function _applyAspect(
485 : $targetClass, AspectDefinition $aspectDefinition, IDispatcher $dispatcher
486 : ) {
487 25 : $rClass = $this->_reflectionFactory->getClass($targetClass);
488 25 : $aspect = $this->getBean($aspectDefinition->getBeanName());
489 25 : foreach ($aspectDefinition->getPointcuts() as $pointcutName) {
490 25 : $pointcut = $this->_aspectManager->getPointcut($pointcutName);
491 25 : if ($pointcut === false) {
492 1 : throw new BeanFactoryException('Could not find pointcut: ' . $pointcutName);
493 : }
494 24 : $expression = $pointcut->getExpression();
495 24 : foreach ($rClass->getMethods() as $method) {
496 24 : $methodName = $method->getName();
497 24 : if (preg_match('/' . $expression . '/', $methodName) === 0) {
498 8 : continue;
499 : }
500 : if (
501 24 : $aspectDefinition->getType() == AspectDefinition::ASPECT_METHOD
502 24 : ) {
503 21 : $dispatcher->addMethodInterceptor($methodName, $aspect, $pointcut->getMethod());
504 21 : } else {
505 5 : $dispatcher->addExceptionInterceptor($methodName, $aspect, $pointcut->getMethod());
506 : }
507 24 : }
508 24 : }
509 24 : }
510 :
511 : /**
512 : * Applies all aspects specifically defined for this bean definition.
513 : *
514 : * @param BeanDefinition $definition
515 : * @param IDispatcher $dispatcher
516 : *
517 : * @return void
518 : */
519 : private function _applySpecificAspects(BeanDefinition $definition, IDispatcher $dispatcher)
520 : {
521 277 : if ($definition->hasAspects()) {
522 17 : foreach ($definition->getAspects() as $aspect) {
523 17 : $this->_applyAspect($definition->getClass(), $aspect, $dispatcher);
524 17 : }
525 17 : }
526 277 : }
527 :
528 : /**
529 : * Looks for any global aspects that may apply to this bean and applies them.
530 : *
531 : * @param BeanDefinition $definition
532 : * @param IDispatcher $dispatcher
533 : *
534 : * @return void
535 : */
536 : private function _applyGlobalAspects(BeanDefinition $definition, IDispatcher $dispatcher)
537 : {
538 277 : $class = $definition->getClass();
539 277 : $rClass = $this->_reflectionFactory->getClass($class);
540 277 : foreach ($this->_aspectManager->getAspects() as $aspect) {
541 29 : $expression = $aspect->getExpression();
542 29 : if (preg_match('/' . $expression . '/', $class) === 0) {
543 29 : $parentClass = $rClass->getParentClass();
544 29 : while($parentClass !== false) {
545 1 : if (preg_match('/' . $expression . '/', $parentClass->getName()) > 0) {
546 1 : $this->_applyAspect($class, $aspect, $dispatcher);
547 1 : }
548 1 : $parentClass = $parentClass->getParentClass();
549 1 : }
550 29 : } else {
551 7 : $this->_applyAspect($class, $aspect, $dispatcher);
552 : }
553 277 : }
554 277 : }
555 :
556 : /**
557 : * Applies specific bean aspects and global defined aspects.
558 : *
559 : * @param BeanDefinition $definition
560 : *
561 : * @return void
562 : */
563 : private function _applyAspects(BeanDefinition $definition)
564 : {
565 277 : $class = $definition->getClass();
566 277 : $dispatcher = clone $this->_dispatcherTemplate;
567 277 : $this->_applySpecificAspects($definition, $dispatcher);
568 277 : $this->_applyGlobalAspects($definition, $dispatcher);
569 277 : if ($dispatcher->hasMethodsIntercepted()) {
570 24 : $definition->setProxyClassName(
571 24 : $this->_proxyFactory->create($class, $dispatcher)
572 24 : );
573 24 : }
574 277 : }
575 : /**
576 : * This will create a new bean, injecting all properties and applying all
577 : * aspects.
578 : *
579 : * @throws BeanFactoryException
580 : * @return object
581 : */
582 : private function _createBean(BeanDefinition $definition)
583 : {
584 277 : $this->_lifecycleManager->beforeCreate($definition);
585 277 : $this->_createBeanDependencies($definition);
586 277 : $this->_applyAspects($definition);
587 277 : $bean = $this->_instantiate($definition);
588 277 : if (!is_object($bean)) {
589 1 : throw new BeanFactoryException(
590 1 : 'Could not instantiate ' . $definition->getName()
591 1 : );
592 : }
593 277 : $this->_assemble($bean, $definition);
594 277 : $this->_setupInitAndShutdown($bean, $definition);
595 277 : $this->_lifecycleManager->afterCreate($bean, $definition);
596 277 : return $bean;
597 : }
598 :
599 : /**
600 : * Calls init method and register shutdown method.
601 : *
602 : * @param object $bean
603 : * @param BeanDefinition $definition
604 : *
605 : * @return void
606 : */
607 : private function _setupInitAndShutdown($bean, BeanDefinition $definition)
608 : {
609 277 : if ($definition->hasInitMethod()) {
610 33 : $initMethod = $definition->getInitMethod();
611 33 : $bean->$initMethod();
612 33 : }
613 277 : if ($definition->hasDestroyMethod()) {
614 32 : $destroyMethod = $definition->getDestroyMethod();
615 32 : $this->registerShutdownMethod($bean, $destroyMethod);
616 32 : }
617 277 : }
618 :
619 : /**
620 : * Tries to inject by looking up set* methods.
621 : *
622 : * @param object $bean
623 : * @param string $name
624 : * @param string $value
625 : *
626 : * @return boolean
627 : */
628 : private function _setterInject($bean, $name, $value)
629 : {
630 277 : $methodName = 'set' . ucfirst($name);
631 277 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
632 277 : if ($rClass->hasMethod($methodName)) {
633 277 : $bean->$methodName($value);
634 277 : return true;
635 : }
636 18 : return false;
637 : }
638 :
639 : /**
640 : * Tries to inject by looking up a property by name.
641 : *
642 : * @param object $bean
643 : * @param string $name
644 : * @param string $value
645 : *
646 : * @return boolean
647 : */
648 : private function _propertyInject($bean, $name, $value)
649 : {
650 18 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
651 18 : if ($rClass->hasProperty($name)) {
652 17 : $rProperty = $rClass->getProperty($name);
653 17 : if (!$rProperty->isPublic()) {
654 11 : $rProperty->setAccessible(true);
655 11 : }
656 17 : $rProperty->setValue($bean, $value);
657 17 : return true;
658 : }
659 1 : return false;
660 : }
661 : /**
662 : * Assembles a bean (setter injection)
663 : *
664 : * @param mixed $bean
665 : * @param BeanDefinition $beanDefinition
666 : *
667 : * @return void
668 : */
669 : private function _assemble($bean, BeanDefinition $beanDefinition)
670 : {
671 277 : $this->_lifecycleManager->beforeAssemble($bean, $beanDefinition);
672 277 : foreach ($beanDefinition->getProperties() as $property) {
673 277 : $propertyName = $property->getName();
674 277 : $propertyValue = $this->_getValueFromDefinition($property);
675 : if (
676 277 : $this->_setterInject($bean, $propertyName, $propertyValue)
677 18 : || $this->_propertyInject($bean, $propertyName, $propertyValue)
678 277 : ) {
679 277 : continue;
680 : }
681 1 : throw new BeanFactoryException("Dont know how to inject: $propertyName");
682 277 : }
683 277 : $this->fillAware($beanDefinition, $bean);
684 277 : $this->_lifecycleManager->afterAssemble($bean, $beanDefinition);
685 277 : }
686 : /**
687 : * Returns a bean.
688 : *
689 : * @param string $name Bean name.
690 : *
691 : * @throws BeanFactoryException
692 : * @return object
693 : */
694 : public function getBean($name)
695 : {
696 277 : $ret = false;
697 277 : $beanDefinition = $this->getBeanDefinition($name);
698 277 : $beanName = $name . '.bean';
699 277 : if ($beanDefinition->isAbstract()) {
700 1 : throw new BeanFactoryException(
701 1 : "Cant instantiate abstract bean: $name"
702 1 : );
703 : }
704 277 : if ($beanDefinition->isPrototype()) {
705 38 : $ret = $this->_createBean($beanDefinition);
706 277 : } else if ($beanDefinition->isSingleton()) {
707 277 : if (isset($this->_beans[$beanName])) {
708 175 : $ret = $this->_beans[$beanName];
709 175 : } else {
710 277 : $ret = $this->_beanCache->fetch($beanName, $result);
711 277 : if (!$ret) {
712 277 : $ret = $this->_createBean($beanDefinition);
713 277 : }
714 277 : $this->_beans[$beanName] = $ret;
715 : }
716 277 : }
717 277 : return $ret;
718 : }
719 :
720 : /**
721 : * This will return a container
722 : *
723 : * @param array $properties Container properties.
724 : *
725 : * @return ContainerImpl
726 : */
727 : public static function getInstance(array $properties = array())
728 : {
729 277 : if (self::$_containerInstance === false) {
730 : // Init cache subsystems.
731 277 : if (isset($properties['ding']['cache'])) {
732 158 : CacheLocator::configure($properties['ding']['cache']);
733 158 : }
734 277 : \Ding\Autoloader\Autoloader::setCache(CacheLocator::getAutoloaderCacheInstance());
735 277 : if (isset($properties['ding']['log4php.properties'])) {
736 277 : \Logger::configure($properties['ding']['log4php.properties']);
737 277 : }
738 277 : self::$_containerInstance = new ContainerImpl($properties['ding']['factory']);
739 273 : }
740 273 : return self::$_containerInstance;
741 : }
742 :
743 : /**
744 : * Register a shutdown (destroy-method) method for a bean.
745 : *
746 : * @param object $bean Bean to call.
747 : * @param string $method Method to call.
748 : *
749 : * @see Ding\Container.IContainer::registerShutdownMethod()
750 : *
751 : * @return void
752 : */
753 : public function registerShutdownMethod($bean, $method)
754 : {
755 32 : $this->_shutdowners[] = array($bean, $method);
756 32 : }
757 :
758 : /**
759 : * Destructor, will call all beans destroy-methods.
760 : *
761 : * @return void
762 : */
763 : public function __destruct()
764 : {
765 16 : foreach ($this->_shutdowners as $shutdownCall) {
766 16 : $bean = $shutdownCall[0];
767 16 : $method = $shutdownCall[1];
768 16 : $bean->$method();
769 16 : }
770 16 : }
771 :
772 : /**
773 : *
774 : * Enter description here ...
775 : * @param unknown_type $messageSource
776 : */
777 : public function setMessageSource(IMessageSource $messageSource)
778 : {
779 14 : $this->_messageSource = $messageSource;
780 14 : }
781 :
782 : /**
783 : * (non-PHPdoc)
784 : * @see Ding\MessageSource.IMessageSource::getMessage()
785 : */
786 : public function getMessage($bundle, $message, array $arguments, $locale = 'default')
787 : {
788 : return
789 3 : $this->_messageSource !== false
790 3 : ? $this->_messageSource->getMessage($bundle, $message, $arguments, $locale)
791 3 : : NULL;
792 : }
793 :
794 : /**
795 : * (non-PHPdoc)
796 : * @see Ding\Resource.IResourceLoader::getResource()
797 : */
798 : public function getResource($location, $context = false)
799 : {
800 : // Missing scheme?
801 8 : $scheme = strpos($location, '://');
802 8 : if ($scheme === false) {
803 1 : $location = FilesystemResource::SCHEME . $location;
804 1 : }
805 : // Already served?
806 8 : if (isset($this->_resources[$location])) {
807 1 : return $this->_resources[$location];
808 : }
809 : // See what kind of resource to return.
810 8 : if (strpos($location, FilesystemResource::SCHEME) === 0) {
811 3 : $resource = new FilesystemResource($location, $context);
812 8 : } else if (strpos($location, IncludePathResource::SCHEME) === 0) {
813 4 : $resource = new IncludePathResource($location, $context);
814 4 : } else {
815 1 : $resource = new URLResource($location, $context);
816 : }
817 8 : $this->_resources[$location] = $resource;
818 8 : return $resource;
819 : }
820 :
821 : /**
822 : * (non-PHPdoc)
823 : * @see Ding\Bean.IBeanDefinitionProvider::getBeansListeningOn()
824 : */
825 : public function getBeansListeningOn($eventName)
826 : {
827 14 : if (isset($this->_eventListeners[$eventName])) {
828 1 : return $this->_eventListeners[$eventName];
829 : }
830 13 : return array();
831 : }
832 :
833 : /**
834 : * (non-PHPdoc)
835 : * @see Ding\Container.IContainer::eventDispatch()
836 : */
837 : public function eventDispatch($eventName, $data = null)
838 : {
839 14 : $listeners = $this->getBeansListeningOn($eventName);
840 14 : foreach ($this->_beanDefinitionProviders as $provider) {
841 14 : $listeners = array_merge($listeners, $provider->getBeansListeningOn($eventName));
842 14 : }
843 14 : $eventName = 'on' . ucfirst($eventName);
844 14 : foreach ($listeners as $beanName) {
845 5 : $bean = $this->getBean($beanName);
846 5 : $bean->$eventName($data);
847 14 : }
848 14 : }
849 :
850 : /**
851 : * (non-PHPdoc)
852 : * @see Ding\Container.IContainer::eventListen()
853 : */
854 : public function eventListen($eventName, $beanName)
855 : {
856 1 : if (!isset($this->_eventListeners[$eventName])) {
857 1 : $this->_eventListeners[$eventName] = array();
858 1 : }
859 1 : $this->_eventListeners[$eventName][] = $beanName;
860 1 : }
861 :
862 : /**
863 : * (non-PHPdoc)
864 : * @see Ding\Container.IContainer::registerBeanDefinitionProvider()
865 : */
866 : public function registerBeanDefinitionProvider(IBeanDefinitionProvider $provider)
867 : {
868 277 : $this->_beanDefinitionProviders[] = $provider;
869 277 : }
870 :
871 : /**
872 : * If we dont have a ReflectionFactory yet (i.e: didnt make the call to
873 : * getBean() yet), replace it with this one.
874 : *
875 : * @param string $class The name of a class.
876 : *
877 : * @return ReflectionClass
878 : */
879 : protected function getClass($class)
880 : {
881 277 : return new \ReflectionClass($class);
882 : }
883 :
884 : /**
885 : * Will look for "aware" kind of interfaces and inject whatever necessary.
886 : *
887 : * @param BeanDefinition $def The Bean Definition
888 : * @param object $bean The bean
889 : *
890 : * @return void
891 : */
892 : public function fillAware(BeanDefinition $def, $bean)
893 : {
894 277 : $class = get_class($bean);
895 277 : $rClass = $this->_reflectionFactory->getClass($class);
896 277 : if ($rClass->implementsInterface('Ding\Reflection\IReflectionFactoryAware')) {
897 277 : $bean->setReflectionFactory($this->_reflectionFactory);
898 277 : }
899 277 : if ($rClass->implementsInterface('Ding\Bean\IBeanNameAware')) {
900 1 : $bean->setBeanName($def->getName());
901 1 : }
902 277 : if ($rClass->implementsInterface('Ding\Logger\ILoggerAware')) {
903 198 : $bean->setLogger(\Logger::getLogger($class));
904 198 : }
905 277 : if ($rClass->implementsInterface('Ding\Container\IContainerAware')) {
906 277 : $bean->setContainer($this);
907 277 : }
908 277 : if ($rClass->implementsInterface('Ding\Resource\IResourceLoaderAware')) {
909 273 : $bean->setResourceLoader($this);
910 273 : }
911 277 : if ($rClass->implementsInterface('Ding\Aspect\IAspectManagerAware')) {
912 277 : $bean->setAspectManager($this->_aspectManager);
913 277 : }
914 :
915 277 : if ($rClass->implementsInterface('Ding\Bean\IBeanDefinitionProvider')) {
916 277 : $this->registerBeanDefinitionProvider($bean);
917 277 : }
918 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterConfigListener')) {
919 277 : $this->_lifecycleManager->addAfterConfigListener($bean);
920 277 : }
921 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterDefinitionListener')) {
922 273 : $this->_lifecycleManager->addAfterDefinitionListener($bean);
923 273 : }
924 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeCreateListener')) {
925 1 : $this->_lifecycleManager->addBeforeCreateListener($bean);
926 1 : }
927 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterCreateListener')) {
928 273 : $this->_lifecycleManager->addAfterCreateListener($bean);
929 273 : }
930 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeAssembleListener')) {
931 1 : $this->_lifecycleManager->addBeforeAssembleListener($bean);
932 1 : }
933 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterAssembleListener')) {
934 1 : $this->_lifecycleManager->addAfterAssembleListener($bean);
935 1 : }
936 277 : if ($rClass->implementsInterface('Ding\Aspect\IAspectProvider')) {
937 197 : $this->_aspectManager->registerAspectProvider($bean);
938 193 : }
939 277 : if ($rClass->implementsInterface('Ding\Aspect\IPointcutProvider')) {
940 193 : $this->_aspectManager->registerPointcutProvider($bean);
941 193 : }
942 277 : }
943 :
944 : /**
945 : * Called when a signal is caught.
946 : *
947 : * @param integer $signo
948 : *
949 : * @return void
950 : */
951 : public function signalHandler($signo)
952 : {
953 2 : $msg = "Caught Signal: $signo";
954 2 : $this->_logger->warn($msg);
955 2 : $this->eventDispatch('dingSignal', $signo);
956 2 : }
957 :
958 : /**
959 : * Called by php after set_error_handler()
960 : *
961 : * @param integer $type
962 : * @param string $message
963 : * @param string $file
964 : * @param integer $line
965 : *
966 : * @return true
967 : */
968 : public function errorHandler($type, $message, $file, $line)
969 : {
970 11 : $msg = "$message in $file:$line";
971 11 : if ($msg == $this->_lastErrorMessage) {
972 1 : return;
973 : }
974 11 : $this->_lastErrorMessage = $msg;
975 11 : $this->_logger->error($msg);
976 11 : $this->eventDispatch(
977 11 : 'dingError', new ErrorInfo($type, $message, $file, $line)
978 11 : );
979 11 : return true;
980 : }
981 :
982 : // @codeCoverageIgnoreStart
983 : /**
984 : * Called by the vm after register_shutdown_function()
985 : *
986 : * @return void
987 : */
988 : public function shutdownHandler()
989 : {
990 : $msg = "Shutting down";
991 : $this->eventDispatch('dingShutdown');
992 : }
993 : // @codeCoverageIgnoreEnd
994 :
995 : /**
996 : * (non-PHPdoc)
997 : * @see Ding\Container.IContainer::registerProperties()
998 : */
999 : public function registerProperties(array $properties)
1000 : {
1001 277 : foreach ($properties as $key => $value) {
1002 49 : if (strncmp($key, 'php.', 4) === 0) {
1003 2 : ini_set(substr($key, 4), $value);
1004 2 : }
1005 49 : $this->_properties['${' . $key . '}'] = $value;
1006 277 : }
1007 277 : }
1008 :
1009 : /**
1010 : * Constructor.
1011 : *
1012 : * @param array $options options.
1013 : *
1014 : * @return void
1015 : */
1016 : protected function __construct(array $options)
1017 : {
1018 : // Setup logger.
1019 277 : $this->_logger = \Logger::getLogger(get_class($this));
1020 277 : $this->_logDebugEnabled = $this->_logger->isDebugEnabled();
1021 277 : $soullessArray = array();
1022 277 : $this->_beanAliases = $soullessArray;
1023 277 : $this->_beanDefs = $soullessArray;
1024 277 : $this->_beans = $soullessArray;
1025 277 : $this->_shutdowners = $soullessArray;
1026 277 : $this->_resources = $soullessArray;
1027 277 : $this->_eventListeners = $soullessArray;
1028 277 : $this->_properties = $soullessArray;
1029 :
1030 : // Merge options with our defaults.
1031 277 : self::$_options = array_replace_recursive(self::$_options, $options);
1032 277 : $this->registerProperties(self::$_options['properties']);
1033 277 : $sapi = php_sapi_name();
1034 277 : if ($sapi == 'cgi' || $sapi == 'cli') {
1035 277 : $handler = array($this, 'signalHandler');
1036 277 : foreach ($this->_signals as $signal) {
1037 277 : pcntl_signal($signal, $handler);
1038 277 : }
1039 277 : pcntl_sigprocmask(SIG_UNBLOCK, $this->_signals);
1040 277 : }
1041 277 : set_error_handler(array($this, 'errorHandler'));
1042 277 : register_shutdown_function(array($this, 'shutdownHandler'));
1043 :
1044 277 : $this->_lifecycleManager = new BeanLifecycleManager;
1045 277 : $this->_dispatcherTemplate = new DispatcherImpl();
1046 277 : $this->_aspectManager = new AspectManager();
1047 277 : $this->_beanDefCache = DummyCacheImpl::getInstance();
1048 277 : $this->_beanCache = DummyCacheImpl::getInstance();
1049 277 : $this->registerBeanDefinitionProvider(new Core(self::$_options));
1050 277 : $this->_reflectionFactory = $this;
1051 277 : $this->_reflectionFactory = $this->getBean('dingReflectionFactory');
1052 277 : $this->_proxyFactory = $this->getBean('dingProxyFactory');
1053 277 : $this->_beanDefCache = $this->getBean('dingDefinitionsCache');
1054 277 : $this->_beanCache = $this->getBean('dingBeanCache');
1055 277 : $this->_lifecycleManager = $this->getBean('dingLifecycleManager');
1056 277 : $this->_aspectManager = $this->getBean('dingAspectManager');
1057 277 : $this->_dispatcherTemplate = $this->getBean('dingAspectCallDispatcher');
1058 :
1059 : // Set drivers
1060 277 : if (isset(self::$_options['bdef']['xml'])) {
1061 169 : $xmlDriver = $this->getBean('dingXmlBeanDefinitionProvider');
1062 167 : }
1063 275 : if (isset(self::$_options['bdef']['yaml'])) {
1064 38 : $yamlDriver = $this->getBean('dingYamlBeanDefinitionProvider');
1065 36 : }
1066 273 : $this->getBean('dingPropertiesDriver');
1067 273 : $this->getBean('dingMessageSourceDriver');
1068 273 : $this->getBean('dingMethodInjectionDriver');
1069 :
1070 : // All set, continue.
1071 273 : if (isset(self::$_options['bdef']['annotation'])) {
1072 111 : $this->getBean('dingAnnotationDiscovererDriver');
1073 111 : $this->getBean('dingAnnotationBeanDefinitionProvider');
1074 111 : $this->getBean('dingAnnotationValueDriver');
1075 111 : $this->getBean('dingAnnotationAspectDriver');
1076 111 : $this->getBean('dingAnnotationResourceDriver');
1077 111 : $this->getBean('dingAnnotationInitDestroyMethodDriver');
1078 111 : $this->getBean('dingAnnotationRequiredDriver');
1079 111 : $this->getBean('dingMvcAnnotationDriver');
1080 111 : }
1081 273 : $this->_lifecycleManager->afterConfig();
1082 273 : }
1083 : }
|